package ch.myDungeons.characters;

import ch.myDungeons.gameObjects.Item;
import ch.myDungeons.gameObjects.Potion;
import ch.myDungeons.io.ItemGenerator;
import ch.myDungeons.io.LanguagePack;
import ch.myDungeons.game.MyDungeon;

/**
 * The player in the game
 * @author Grii
 *
 */


 public class Player extends Person {
	private static final long serialVersionUID = 7435831912019293105L;
	
	/** Experience points towards the next level */
	private int xpPoints = 0;
	
	public Player (String name) {
		super(name, 1);
		setCurrentHP(getMaxHP());
		setCurrentMP(getMaxMP());
	}
	
	/** Executed every turn. Runs the last command in the console */
	public boolean doTurn(String command){
		super.doTurn();
		boolean result = interpretCommand(command);
		checkLevelup();
		return result;
	}
	
	/** Executes the command */
	private boolean interpretCommand(String command) {
		if (command.equals("up")) {
			if (attackDirection(0));
			else if(move(0));
			else return false;
		} 
		else if (command.equals("down")) {
			if (attackDirection(2));
			else if(move(2));
			else return false;
		} 
		else if (command.equals("left")) {
			if (attackDirection(3));
			else if(move(3));
			else return false;
		} 
		else if (command.equals("right")) {
			if (attackDirection(1));
			else if(move(1));
			else return false;
		}
		else if (command.equals("wait")) {
			setCurrentHP(getCurrentHP() + getLevel());
			if (getCurrentHP() > getMaxHP()) {
				setCurrentHP(getMaxHP());
			}
			setCurrentMP(getCurrentMP() + 1);
			if (getCurrentMP() > getMaxMP()) {
				setCurrentMP(getMaxMP());
			}
			return true;
		}
		else if (command.equals("list") || command.equals("l")) {
			if (getMap().tiles[getPosX()][getPosY()].inventory.size() == 0) {
				console.println(LanguagePack.get("no_items_on_this_tile"));
			} else {
				if(getMap().tiles[getPosX()][getPosY()].inventory.size() == 1){
					console.println(getMap().tiles[getPosX()][getPosY()].inventory.size() + " " + LanguagePack.get("item_on_this_tile") + ":");
				} else {
					console.println(getMap().tiles[getPosX()][getPosY()].inventory.size() + " " + LanguagePack.get("items_on_this_tile") + ":");
				}
			}
			for (int i = 0; i < getMap().tiles[getPosX()][getPosY()].inventory.size(); i++) {
				console.println(i + ": " + getMap().tiles[getPosX()][getPosY()].inventory.get(i).getNameWithCount());
			}
			return false;
		} 
		else if (command.equals("inventory") || command.equals("i")) {
			if (getInventory().size() == 0) {
				console.println(LanguagePack.get("no_items"));
			} else {
				console.println(getInventory().size() + " " + LanguagePack.get("items") + ":");
			}
			for (int i = 0; i < getInventory().size(); i++) {
				console.println(i + ": " + getInventory().get(i).getNameWithCount());
			}
			return false;
		} 
		else if (command.matches("drink\\s\\d+")) {
			int itemIndex = Integer.parseInt(command.split("\\s")[1]);
			if (itemIndex < getInventory().size() && itemIndex >= 0) {
				if(drinkPotion(itemIndex));
			} else {
				console.println(LanguagePack.get("no_such_item") + " (" + itemIndex + ")");
			}
			return false;
		} 
		else if (command.matches("e\\s\\d+") || command.matches("equip\\s\\d+")) {
			int itemIndex = Integer.parseInt(command.split("\\s")[1]);
			if (itemIndex < getInventory().size() && itemIndex >= 0) {
				boolean success = equipItem(itemIndex);
				if(success){
					console.println(getInventory().get(itemIndex).getItem().getName() + " " + LanguagePack.get("equipped"));
				} else {
					console.println(LanguagePack.get("you_cannot_equip") + " " + getInventory().get(itemIndex).getItem().getName());
				}
			} else {
				console.println(LanguagePack.get("no_such_item") + " (" + itemIndex + ")");
			}
			return false;
		} 
		else if (command.equals("p all") || command.equals("pickup all")) {
			int itemCount = pickUpAll();
			if (itemCount <= 0) {
				console.println(LanguagePack.get("no_items_on_this_tile"));
			}
			return false;
		} 
		else if (command.matches("p\\s\\d+") || command.matches("pickup\\s\\d+")) {
			int itemIndex = Integer.parseInt(command.split("\\s")[1]);
			if (itemIndex < getMap().tiles[getPosX()][getPosY()].inventory.size() && itemIndex >= 0) {
				console.println(getMap().tiles[getPosX()][getPosY()].inventory.get(itemIndex).getItem().getName() + " " + LanguagePack.get("picked_up"));
			} else {
				console.println(LanguagePack.get("no_such_item") + " (" + itemIndex + ")");
			}
			pickUp(itemIndex);
			return false;
		} 
		else if (command.matches("d\\s\\d+") || command.matches("drop\\s\\d+")) {
			int itemIndex = Integer.parseInt(command.split("\\s")[1]);
			if (drop(itemIndex)) {
				console.println(getMap().tiles[getPosX()][getPosY()].inventory.get(getMap().tiles[getPosX()][getPosY()].inventory.size()-1).getItem().getName() + " " + LanguagePack.get("dropped"));
			} else {
				console.println(LanguagePack.get("no_such_item") + " (" + itemIndex + ")");
			}
			return false;
		} 
		else if (command.matches("throw\\s\\d+\\s\\d+")) {
			int itemIndex = Integer.parseInt(command.split("\\s")[1]);
			int direction = Integer.parseInt(command.split("\\s")[2]) % 4;
			String itemName = "item";
			if(getInventory().size() > itemIndex && itemIndex >= 0){
				itemName = getInventory().get(itemIndex).getItem().getName();
			}
			
			if (throwItem(direction, itemIndex)) {
				console.println(LanguagePack.get("you_threw_a") + " " + itemName + " ");
				return true;
			} else {
				console.println(LanguagePack.get("no_such_item") + " (" + itemIndex + ")");
			}
			return false;
		}
		else if (command.equals("hero") || command.equals("h") || command.equals(name.toLowerCase())) {
			console.println(getInfo());
			return false;
		}
		else if (command.equals("<")) {
			if(getMap().tiles[getPosX()][getPosY()].isStairsUp){
				MyDungeon.game.changeLevel(true);
			}else{
				console.println(LanguagePack.get("no_stairs_here"));
			}
			return false;
		}
		else if (command.equals(">")) {
			if(getMap().tiles[getPosX()][getPosY()].isStairsDown){
				MyDungeon.game.changeLevel(false);
			}else{
				console.println(LanguagePack.get("no_stairs_here"));
			}
			return false;
		}
		else if (command.matches("cheat_additem\\s\\w+")) {
			String itemName = command.split("\\s")[1].replaceAll("_", " ");
			Item item = ItemGenerator.createItemFromName(itemName);
			if (item != null) {
				getInventory().addItem(item);
			}
			return false;
		}
		else {return false;}
		return true;
	}

	/** move the player */
	public boolean move(int direction){
		return super.move(direction);
	}
	
	/** Returns the name of the player */
	public String getNameWithPrefix(){
		return name;
	}
	
	/** Attack a target tile. Returns false if failed */
	public boolean attack(int targetX, int targetY){
		boolean result = super.attack(targetX, targetY);
		if (result) {
			NPC target = (NPC)getMap().tiles[targetX][targetY].personOnTheTile;
			if (target.isFriendly()) {
				target.changeFriendly();
			}
			if (target.getCurrentHP() <= 0) {
				setXpPoints(getXpPoints() + target.getExpAward());
				target.die();
			}
		}
		return result;
	}

	/** Attack the person next to this person. Returns false if failed */
	public boolean attackDirection(int direction){
		boolean result =  attack(getMap().getPostitionFromDirection(direction, getPosX(), getPosY())[0], getMap().getPostitionFromDirection(direction, getPosX(), getPosY())[1]);
		return result;
	}
	
	/** Picks up all items */
	public int pickUpAll(){
		int itemCount = getMap().tiles[getPosX()][getPosY()].inventory.size();
		while(!getMap().tiles[getPosX()][getPosY()].inventory.isEmpty()){
			console.println(getMap().tiles[getPosX()][getPosY()].inventory.get(0).getItem().getName() + " " + LanguagePack.get("picked_up"));
			pickUp(0);
		}
		return itemCount;
	}
	
	/** Returns a string containing the stats of the player */
	public String getInfo(){
		String result = "";
		result += LanguagePack.get("name") + ": " + LanguagePack.capitalizeString(name);
		result += "\n" + LanguagePack.get("level") + ": " + getLevel();
		result += "\n" + LanguagePack.get("exp") + ": " + getXpPoints();
		result += "\n" + LanguagePack.get("hitpoints") + ": " + getCurrentHP() + "/" + getMaxHP();
		result += "\n" + LanguagePack.get("manapoints") + ": " + getCurrentMP() + "/" + getMaxMP();
		if (getActiveWeapon() != null) {
			result += "\n" + LanguagePack.get("weapon") + ": " + LanguagePack.capitalizeString(getActiveWeapon().getName())
					+ " (" + getActiveWeapon().attackDamageDice + "d6 + " + getActiveWeapon().attackDamageBonus + " " + LanguagePack.get("damage") + ")";
		} else {
			result += "\n" + LanguagePack.get("weapon") + ": " + LanguagePack.capitalizeString(getNaturalWeapon())
					+ " (" + getBaseAttackDice() + "d6 + " + getBaseAttackBonus() + " " + LanguagePack.get("damage") + ")";
		}
		if (getActiveArmor() != null) {
			result += "\n" + LanguagePack.capitalizeString(LanguagePack.get("armor")) + ": " + LanguagePack.capitalizeString(getActiveArmor().getName())
					+ " (+" + getActiveArmor().armorBonus + " " + LanguagePack.get("armor") + ")";
		} else {
			result += "\n" + LanguagePack.get("armor_no_armor") + " (+" + getNaturalDamageResistance() + " " + LanguagePack.get("armor") + ")";
		}
		return result;
	}
	
	public boolean drinkPotion(int itemIndex){
		boolean result;
		if (getInventory().get(itemIndex).getItem() instanceof Potion) {
			console.println(LanguagePack.get("you_drink_a") + " " + getInventory().get(itemIndex).getItem().getName());
			result = super.drinkPotion(itemIndex);
		} else {
			console.println(itemIndex + " " + LanguagePack.get("is_no_potion"));
			result = false;
		}
		return result;
	}
	
	/** Checks if the player has a levelup */
	public void checkLevelup(){
		if (getXpPoints() >= getLevel() * 100) {
			levelup();
		}
	}
	
	/** Levels the player up */
	private void levelup(){
		setLevel(getLevel() + 1);
		setMaxHP(getMaxHP() + 50);
		setMaxMP(getMaxMP() + 50);
		setCurrentHP(getMaxHP());
		setCurrentMP(getMaxMP());
		console.println(LanguagePack.get("level_up"));
	}
	
	/** Returns name, level, maxHP, maxMP, currentHP, currentMP, friendly, naturalWeapon, baseAttackBonus, baseAttackDice, naturalDamageResistance, activeWeaponIndex, activeArmorIndex, items, xpPoints, true */
	public String getSave(){
		String result = super.getSave();
		result += "<PERSONINFO>" + getXpPoints() + "<PERSONINFO>true";
		return result;
	}

	public int getXpPoints() {
		return xpPoints;
	}

	public void setXpPoints(int xpPoints) {
		this.xpPoints = xpPoints;
	}
}
